/*
 * SpeakerRecog.c
 *
 * Created: 28/01/2014 19:32:38
 *  Author: edielsonpf
 */ 

#include "../MelCeps/MelCeps.h"
#include "../DSPTools/DSPTools.h"
#include "../Recognition/GMMRecognition.h"
#include "SpeakerRecog.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"

/*********************************************************
    private constants.
*********************************************************/
#define	MEL_COEFFICIENTES		12	//1/1000
#define GMM_MIXTURE_FILE_NAME	"mixture.dat"
/*********************************************************
    private types.
*********************************************************/
typedef struct tag_Feature
{
	double* pdFeature;   // feature vector pointer
	int iDimension;		// feature vector dimension
	
	struct tag_Feature* ptagNext;
}ttag_Feature;

typedef struct tag_SpeakerRecog
{
	ttag_Feature* ptagFeatureFirst;
	ttag_Feature* ptagFeatureLast;
	
	Handle hMelCeps;
	Handle hGMM;
	
}ttag_SpeakerRecog;

/*********************************************************
    private variable.
*********************************************************/

/*********************************************************
    private operations.
*********************************************************/

Bool8	SpeakerRecog_addFeature(Handle hHandle, double* pdFeature, int iDimension);

/*

	Creates the class instance. 

	@param	
	@param	
	@param	
		
	@return Handle - The class handler 
	
	@author edielsonpf
	@date   12/02/2014
*/
Handle SpeakerRecog_new(int iSampleRate, long lWindowSize)
{
	ttag_SpeakerRecog* ptagRecog = (ttag_SpeakerRecog*)malloc(sizeof(ttag_SpeakerRecog));
	if(ptagRecog)
	{
		ptagRecog->ptagFeatureFirst = NULL;
		ptagRecog->ptagFeatureLast = NULL;
		
		ptagRecog->hMelCeps = (Handle)MelCeps_new(iSampleRate, lWindowSize);
		if(!ptagRecog->hMelCeps)
		{
			free(ptagRecog);
			ptagRecog = NULL;
		}
		ptagRecog->hGMM = (Handle)GMMRecognition_new((pInt8)GMM_MIXTURE_FILE_NAME);
		if(!ptagRecog->hGMM)
		{
			if(ptagRecog->hMelCeps) MelCeps_delete(ptagRecog->hMelCeps);
			free(ptagRecog);
			ptagRecog = NULL;
		}
	}
	return (Handle)ptagRecog;
}

/*

	Deletes the class instance. 

	@param	
	@param	
	@param	
		
	@return Handle - The class handler 
	
	@author edielsonpf
	@date   12/02/2014
*/
Bool8 SpeakerRecog_delete(Handle hHandle)
{
	if(!hHandle) return False8;
	ttag_SpeakerRecog* ptagRecog = (ttag_SpeakerRecog*)hHandle;
	ttag_Feature* ptagListAux = NULL;
	ttag_Feature* ptagListRun = ptagRecog->ptagFeatureFirst;
	
	MelCeps_delete(ptagRecog->hMelCeps);
	
	/*Delete list*/
	while(ptagListRun)
	{
		ptagListAux=ptagListRun;
		ptagListRun = ptagListRun->ptagNext;
		free(ptagListAux);
	}
	free(ptagRecog);
	return True8;
}

/*

	. 

	@param	
	@param	
		
	@return 
	
	@author edielsonpf
	@date   13/02/2014
*/
Bool8 SpeakerRecog_addFeature(Handle hHandle, double* pdFeature, int iDimension)
{
	if(!hHandle)	return False8;
	if(!pdFeature)	return False8;
	
	ttag_SpeakerRecog* ptagSpeakerRecog = (ttag_SpeakerRecog*)hHandle;
	ttag_Feature* ptagListAux = NULL;
	Bool8 bResult=False8;
	
	
	ptagListAux = (ttag_Feature*)malloc(sizeof(ttag_Feature));
	if(ptagListAux)
	{
		ptagListAux->ptagNext = NULL;
		ptagListAux->pdFeature = malloc(sizeof(iDimension));
		if(ptagListAux->pdFeature)
		{
			memcpy(ptagListAux->pdFeature,pdFeature,iDimension);
			ptagListAux->iDimension = iDimension;
		}
		
		if(ptagSpeakerRecog->ptagFeatureFirst == NULL)
		{
			ptagSpeakerRecog->ptagFeatureFirst = ptagListAux;
			ptagSpeakerRecog->ptagFeatureLast = ptagListAux;
		}
		else
		{
			(ptagSpeakerRecog->ptagFeatureLast)->ptagNext = ptagListAux;
			ptagSpeakerRecog->ptagFeatureLast = ptagListAux;
		}
		bResult = True8;
	}
	return bResult;
}
/*

	Extract feature from the audio window and add to the feature list. 

	@param	double* pdAudioData - Input vector with data for coefficients extraction 
	@param	long lAudioDataSize - Input vector size. Must be the same size of audio window size. 
		
	@return Bool8 - True8 if succeeded or False8 otherwise 
	
	@author edielsonpf
	@date   13/02/2014
*/
Bool8 SpeakerRecog_extractFeature(Handle hHandle, double* pdAudioWindow, long lWindowSize)
{
	if(!pdAudioWindow)	return False8;
	if(!hHandle)		return False8;
	
	ttag_SpeakerRecog* ptagSpeakerRecog = (ttag_SpeakerRecog*)hHandle;
	
	Bool8 bResult = False8;
	double* pdMelCoef = NULL;
	
	pdMelCoef = malloc(sizeof(double_t)*MEL_COEFFICIENTES);
	if(pdMelCoef)
	{
		if(MelCeps_extract(ptagSpeakerRecog->hMelCeps,pdAudioWindow,lWindowSize,pdMelCoef,MEL_COEFFICIENTES) == MEL_COEFFICIENTES)
		{
				//Add to linked list
				bResult = SpeakerRecog_addFeature((Handle)ptagSpeakerRecog,pdMelCoef,MEL_COEFFICIENTES);
				free(pdMelCoef);	
		}
	}
	return bResult;
}

/*

	Calculates the probability. 

	@param	Handle - The class handler 
			
	@return double - returns the probability 
	
	@author edielsonpf
	@date   13/02/2014
*/
double SpeakerRecog_verify(Handle hHandle)
{
	if(!hHandle) return 0;
	
	ttag_SpeakerRecog* ptagSpeakerRecog = (ttag_SpeakerRecog*)hHandle;
	double dProbability=0;
	
	if(ptagSpeakerRecog->ptagFeatureFirst)
	{
		ttag_Feature* ptagListAux = ptagSpeakerRecog->ptagFeatureFirst;
		while(ptagListAux)
		{
			dProbability+= GMMRecognition_aposteriori(ptagSpeakerRecog->hGMM,ptagListAux->pdFeature,ptagListAux->iDimension);
			ptagListAux=ptagListAux->ptagNext;
		}
	}
	return dProbability;
}